﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;

namespace Dynamic01
{
    public class Program
    {
        public static void Main(string[] args)
        {
            dynamic student;
            dynamic teacher;
            dynamic employee;

            student = new DynamicBag();
            student.Name = "Billy";
            student.Age = 12;

            teacher = new DynamicBag();
            teacher.Name = "Ms. Anderson";
            teacher.Age = "thirty";

            WritePerson(student);
            WritePerson(teacher);

            employee = new DynamicBag();
            employee.Name = "Mr. Smith";
            employee.Age = 42;
            employee.CelebrateBirthday = (Action<dynamic>)(person => person.Age++);

            WritePerson(employee);
            employee.CelebrateBirthday(employee);
            WritePerson(employee);

            dynamic adder = new Add();
            Console.WriteLine("Adding: {0}", adder(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
            Console.WriteLine("Adding: {0}", adder("Hello ", "world!"));

            Console.WriteLine(student.FavoriteColor);
        }

        private static void WritePerson(dynamic person)
        {
            Console.WriteLine("{0} is {1} years old.", person.Name, person.Age);
        }
    }

    public class Add : DynamicObject
    {
        public Add()
            : base()
        {
            Console.WriteLine("Creating the adder...");
        }

        public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
        {
            dynamic total = args[0];
            for (int index = 1; index < args.Length; index++)
            {
                dynamic value = args[index];
                total += value;
            }
            result = total;
            return true;
        }
    }

    /// <summary>
    /// This works a lot like an ExpandoObject.
    /// </summary>
    public class DynamicBag : DynamicObject
    {
        private Dictionary<string, object> _items;

        public DynamicBag()
        {
            _items = new Dictionary<string, object>();
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return _items.TryGetValue(binder.Name, out result);
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _items[binder.Name] = value;
            return true;
        }
    }
}